﻿package com.shootingGame.renderableClasses
{
	import com.shootingGame.GamePlayManager;
	import com.shootingGame.HealthBar;
	import com.shootingGame.physics.collisionReactionClasses.base.CollisionEffects;
	
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	public class GameObject extends MovieClip implements IRendered
	{
		public var id:int;
		public var model:MovieClip;
		public var memoryX:Number;
		public var memoryY:Number;
		private var _facing : Number;
		public var attachments:Array;
		private var attachmentsContainer:MovieClip;
		private var _preferredCentre : Point;
		//When this is true, the object will be pushed on to the renderables list.
		public var isToBeRendered : Boolean;
		//Enables/Disables rendering for an object on the renderables list.
		//This applies only when isToBeRendered is true.
		public var isRenderingEnabled : Boolean;
		public var isToBeUpdated : Boolean;
		public var isInvulnerable : Boolean;
		public var isHitDetectionEnabled : Boolean;
		public var canRegisterOrdinanceImpact : Boolean;
		private var _hitPoints : int;
		private var _hitPointMax : int;
		protected var _isExpired : Boolean;
		private var healthBar : HealthBar;
		protected var isViewAreaRenderOnly:Boolean;
		public var collisionEffects : CollisionEffects;
		
		public function GameObject(model:MovieClip, xPos:Number = 0, yPos:Number = 0){
			if(model!=null)
				addChild(model);			
			this.model = model;
			this.memoryX = xPos;
			this.memoryY = yPos;
			facing = 0;
			isRenderingEnabled = false;
			isToBeRendered = false;
			isToBeUpdated = false;
			visible = false;
			if(model.healthBar)
				this.healthBar = model.healthBar;
			addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
			addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
		}
		
		virtual public function update():void{
			if(isExpired)
				return;
			else{
				if(isViewAreaRenderOnly){
					if(isInViewRect()){
						isRenderingEnabled = true;
						visible = true;
//						GamePlayManager.instance.renderablesList.push(this);
					}
					else{
						isRenderingEnabled = false;
						visible = false;
//						var renderablesList : Array = GamePlayManager.instance.renderablesList;
//						renderablesList.splice(renderablesList.indexOf(this),1);
					}
				}
			}
		}
				
		virtual public function render():void{
			if(isToBeRendered && isRenderingEnabled){
				if(!visible)
					visible = true;
				x = memoryX;
				y = memoryY;
				rotation = facing;
			}
		}
		
		
		virtual public function addAttachment(attch : AttachableObject) : void {
			if(attch.attachedTo == this){
				if(!attachments)
					attachments = new Array();
				if(!attachmentsContainer){
					attachmentsContainer = new MovieClip();
					model.addChild(attachmentsContainer)
				}
				attachments.push(attch);
				attachmentsContainer.addChild(attch);				
			}
			
		}
		
		virtual public function removeAttachment(attch:AttachableObject) : void {
			if(attch.attachedTo == this){
				attachments.splice(attachments.indexOf(attch), 1);
				attachmentsContainer.removeChild(attch);
				attch.attachedTo = null;
			}
		}
		
		public function get preferredCentre() : Point{
			if(!_preferredCentre)
				_preferredCentre = new Point(0, 0);
			return _preferredCentre;
		}
		
		public function set preferredCentre(value : Point) {
			_preferredCentre = value;
		}
		
		
		virtual protected function onAddedToStage(event : Event) : void {
			if(isToBeUpdated){
				if(isToBeRendered){
					isRenderingEnabled = true;
					GamePlayManager.instance.renderablesList.push(this);
				}
				addObject_ToUpdateList();
			}
		}
		
		//Removes the object from the stage, but does not dispose or remove from the update lists so the object can remain in play or be cached for reuse.
		virtual protected function onRemovedFromStage(event : Event) : void {
			isRenderingEnabled = false;
			var renderablesList : Array = GamePlayManager.instance.renderablesList;
			renderablesList.splice(renderablesList.indexOf(event.currentTarget),1);
			//do not remove the object from update lists here as it may be still in play or it may be cached for use later.
		}
		
		virtual public function addObject_ToStage() : void
		{
			GamePlayManager.instance.generalHolder.addChild(this);
		}
		
		virtual public function removeObject_FromStage() : void {
			if(parent){
				parent.removeChild(this);
			}
		}
		
		virtual public function addObject_ToUpdateList():void{
			if(GamePlayManager.instance.generalList.indexOf(this) == -1)
				GamePlayManager.instance.generalList.push(this);
		}
		
		
		virtual public function removeObject_FromUpdateList():void{
			GamePlayManager.instance.generalList.splice(GamePlayManager.instance.generalList.indexOf(this), 1);
		}
		
		public function get truePosition() : Point{
			return new Point(memoryX, memoryY);
		}
		
		public function set truePosition(value : Point) {
			memoryX = value.x;
			memoryY = value.y;
		}
		
		public function get facing() : Number{
			return _facing;
		}
		
		public function set facing(value:Number){
			if(value >= 360){
				value = value % 360;
			}
			else
				if(value < 0){
					while(value < 0)
						value += 360;
				}
			_facing = value;	
		}
		
		public function get isExpired() : Boolean{
			return _isExpired;
		}
		
		virtual public function set isExpired(value : Boolean) : void{
			if(_isExpired == value)
				return;
			_isExpired = value;
			visible = !value;
			isRenderingEnabled = !value;
			attachments = null;
			if(_isExpired)
				removeObject_FromStage();
		}
		
		public function getCollidablePart() : MovieClip {
			return model.body;
		}
		
		public function isInViewRect() : Boolean {
			var viewRect:Rectangle = GamePlayManager.instance.viewRect;
			
			if(memoryX < viewRect.x || memoryX > viewRect.x + viewRect.width || memoryY < viewRect.y || memoryY > viewRect.y + viewRect.height)
				return false;
			else
				return true;
		}
		
		
		public function get hitPoints() : int{
			return _hitPoints;
		}
		
		public function set hitPoints(value : int) {
			_hitPoints = value;
			if(_hitPoints > _hitPointMax)
				_hitPoints = _hitPointMax;
			else
				if(_hitPoints <= 0){
					_hitPoints = 0;
					isExpired = true;
				}
			if(healthBar){
				healthBar.healthPercentage = _hitPoints / _hitPointMax;
			}
		}
		
		public function get hitPointMax() : int{
			return _hitPointMax;
		}
		
		public function set hitPointMax(value : int) {
			_hitPointMax = value;
		}
	}
}
